/*
test.cpp
----------------------------------------------------------
#include "mlua"

class A
{
public:
    A() {m_x = 0;}

    void setX(int x) {m_x = x;}
    int getX() {return m_x;}

    int m_x;
}

void main()
{
    mlua::MLuaState* ML = MLUA_OPEN();

    MLUA_REG_CLS(A);
    MLUA_REG_CLS_FUNC(A, setX);
    MLUA_REG_CLS_FUNC(A, getX);

    MLUA_EXEC_FILE("test.lua");

    int a = 1;
    int b = 2;
    MLUA_EXEC_FUNC("LuaTest", a, b);

    MLUA_CLOSE();
}
----------------------------------------------------------

test.lua
----------------------------------------------------------
functions LuaTest(a, b)
    local x = A()
    x:setX(a + b)
    print(x:getX()) -- 3
end
----------------------------------------------------------
 */
#ifndef _M_LUA_H_
#define _M_LUA_H_

#include <stdio.h>
#include <vector>
#include <map>
#include <string>

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

using namespace std;

/////////////////////////////////////////////////////////////////////////////////////////////////////////

// default log print method is printf
// please define your self log method, example: #define MLUA_LOG(fmt, ...) Log::Instance()->WriteLog(kLogType_Error, fmt, __VA_ARGS__)
#ifndef MLUA_LOG
#define MLUA_LOG printf
#endif // MLUA_LOG

// open mlua, return MLuaState*
#define MLUA_OPEN() mlua::openLua()

// close mlua, return bool, ML => MLuaState*
#define MLUA_CLOSE() mlua::closeLua(ML)

// register class/struct
#define MLUA_REG_CLS(cls) mlua::regClass<cls>(ML, #cls, mlua::ctor<cls>)
#define MLUA_REG_CLS1(cls, P1) mlua::regClass<cls>(ML, #cls, mlua::ctor<cls, P1>)
#define MLUA_REG_CLS2(cls, P1, P2) mlua::regClass<cls>(ML, #cls, mlua::ctor<cls, P1, P2>)
#define MLUA_REG_CLS3(cls, P1, P2, P3) mlua::regClass<cls>(ML, #cls, mlua::ctor<cls, P1, P2, P3>)
#define MLUA_REG_CLS4(cls, P1, P2, P3, P4) mlua::regClass<cls>(ML, #cls, mlua::ctor<cls, P1, P2, P3, P4>)
#define MLUA_REG_CLS5(cls, P1, P2, P3, P4, P5) mlua::regClass<cls>(ML, #cls, mlua::ctor<cls, P1, P2, P3, P4, P5>)
#define MLUA_REG_CLS6(cls, P1, P2, P3, P4, P5, P6) mlua::regClass<cls>(ML, #cls, mlua::ctor<cls, P1, P2, P3, P4, P5, P6>)
#define MLUA_REG_CLS7(cls, P1, P2, P3, P4, P5, P6, P7) mlua::regClass<cls>(ML, #cls, mlua::ctor<cls, P1, P2, P3, P4, P5, P6, P7>)
#define MLUA_REG_CLS8(cls, P1, P2, P3, P4, P5, P6, P7, P8) mlua::regClass<cls>(ML, #cls, mlua::ctor<cls, P1, P2, P3, P4, P5, P6, P7, P8>)
#define MLUA_REG_CLS9(cls, P1, P2, P3, P4, P5, P6, P7, P8, P9) mlua::regClass<cls>(ML, #cls, mlua::ctor<cls, P1, P2, P3, P4, P5, P6, P7, P8, P9>)

// register class/struct function
#define MLUA_REG_CLS_FUNC(cls, func) mlua::regMethod<cls>(ML, #func, &cls::func)

// register global variable
#define MLUA_REG_VAR(var) mlua::regGlobalVar(ML, #var, var)                              // c++ name == lua name
#define MLUA_REG_VAR2(var, name) mlua::regGlobalVar(ML, name, var)                       // c++ name != lua name

// register constant number
#define MLUA_REG_NUM(n) mlua::regGlobalVar(ML, #n, (int)n)                               // c++ name == lua name
#define MLUA_REG_NUM2(n, name) mlua::regGlobalVar(ML, name, (int)n)                      // c++ name != lua name

// register global function
#define MLUA_REG_FUNC(func) mlua::regFunc(ML, #func, &func)                              // c++ name == lua name
#define MLUA_REG_FUNC2(func, name) mlua::regFunc(ML, name, &func)                        // c++ name != lua name

// execute lua file
#define MLUA_EXEC_FILE(path) mlua::doFile(ML, path)

// execute lua global function, no return value
#define MLUA_EXEC_FUNC(name, ...) {mlua::LuaFunc<void> _tempfunc(ML, name); _tempfunc(__VA_ARGS__);}

// execute lua module function, no return value
#define MLUA_EXEC_MODULE_FUNC(mname, fname, ...) {mlua::LuaFunc<void> _tempfunc(ML, fname, mname); _tempfunc(__VA_ARGS__);}

/////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace mlua 
{
	// func base
	struct Func
	{
		Func() {}
		virtual ~Func() {}
		inline virtual int call(lua_State* L) { return 0; }
		const char* m_name;
	};

	struct Garbage
	{
		void push(Func* f)
		{
			m_Funcs.push_back(f);
		}

		void release()
		{
			for (vector<Func*>::iterator it = m_Funcs.begin(); it != m_Funcs.end(); it++)
			{
				if (*it) delete *it;
			}
			m_Funcs.clear();
		}

	private:
		vector<Func*> m_Funcs;
	};

	struct MLuaState
	{
		lua_State* l;
		Garbage* g;
	};
    
    template<typename T> inline T readValue(lua_State *L, int idx);
    template<typename T> inline T readValue(lua_State* L , const char* name);
    template<typename T> inline void pushValue(lua_State *L, T v);

    inline void pushValue(lua_State *L, const char* v, size_t len) { lua_pushlstring(L, v, len); }
    
    inline void trackStack(lua_State*L, int n)
    {
        lua_Debug d;
        if (lua_getstack(L, n, &d))
        {
            lua_getinfo(L, "Sln", &d);
            if (d.name)
            {
                MLUA_LOG("\tstack[%d] -> line %d : %s()[%s : line %d]\n", n, d.currentline, d.name, d.short_src, d.linedefined);
            }
            else
            {
                MLUA_LOG("\tstack[%d] -> line %d : unknown[%s : line %d]\n", n, d.currentline, d.short_src, d.linedefined);
            }
            trackStack(L, n + 1);
        }
    }

    // error call func
    inline int errorLog(lua_State* L)
    {
        MLUA_LOG("error : %s\n", lua_tostring(L, -1));
        trackStack(L, 0);
		return 0;
    }

    template<typename T>
    struct ClassName
    {
        static inline const char* name() {return m_name;}
        static inline void name(const char* v) {m_name = v;}
        static const char* m_name;
    };
    template<typename T>
    const char* ClassName<T>::m_name = NULL;

    template<typename T>
    struct UserData
    {
        UserData(T* obj, bool isLuaGC = true): m_obj(obj), m_gc(isLuaGC) {}
        ~UserData() {if (m_gc && m_obj) delete m_obj;} 
        T* m_obj;
        bool m_gc;
    };

    struct RefCount
    {
        RefCount(lua_State* L): m_count(1) {}
        ~RefCount() {}
        inline int ref() {return ++m_count;}
        inline int unref() {return --m_count;}
        int m_count;
    };

    // Lua Table
    struct Table
    {
        Table(): m_stackPos(0), m_ref(NULL), m_table(NULL), m_luaState(NULL) {}

        Table(lua_State* L)
        {
            lua_newtable(L);
            m_luaState = L;
            m_stackPos = lua_gettop(L);
            m_table = lua_topointer(L, -1);
            m_ref = new RefCount(L); 
        }

        Table(lua_State* L, int idx)
        {
            m_stackPos = (idx < 0 ? (lua_gettop(L) + 1 + idx) : idx);
            m_luaState = L;
            m_table = lua_topointer(L, m_stackPos);
            m_ref = new RefCount(L); 
        }

        Table(lua_State* L, const char* name)
        {
            lua_getglobal(L, name);
            if (lua_istable(L, -1))
            {
                m_luaState = L;
                m_stackPos = lua_gettop(L);
                m_table = lua_topointer(L, -1);
                m_ref = new RefCount(L);
            }
            else
            {
                MLUA_LOG("%s is not a lua table!\n", name);
            }
        }

        Table(Table const& t)
        {
            m_ref = t.m_ref;
            m_luaState = t.m_luaState;
            m_table = t.m_table;
            m_stackPos = t.m_stackPos;
            if (m_ref) m_ref->ref();
        }

        Table& operator=(const Table& t)
        {
            unref();
            m_ref = t.m_ref;
            m_luaState = t.m_luaState;
            m_table = t.m_table;
            m_stackPos = t.m_stackPos;
            if (m_ref) m_ref->ref();
            return *this;
        }

        ~Table()
        {
            unref();
            m_luaState = NULL;
            m_table = NULL;
        }

        // release
        inline void unref()
        {
            if (m_ref && !m_ref->unref())
            {
                if (valid())
                {
                    lua_remove(m_luaState, m_stackPos);
                }
                delete m_ref;
            }
        }

        // is valid
        inline bool valid()
        {
            if (!m_table) return false;
            return m_table == lua_topointer(m_luaState, m_stackPos);
        }

        template<typename K, typename V>
        inline void set(K k, const V& v)
        {
            if (valid())
            {
                pushValue(m_luaState, k);
                pushValue(m_luaState, v);
                lua_settable(m_luaState, m_stackPos);
            }
        }

        template<typename K>
        inline void set(K k, const char* v, size_t len)
        {
            if (valid())
            {
                pushValue(m_luaState, k);
                pushValue(m_luaState, v, len);
                lua_settable(m_luaState, m_stackPos);
            }
        }

		template<typename K, typename V> inline V get(const K& k);
		template<typename V> inline V get(int k);
		template<typename V> inline V get(const char* k);
		template<typename K> inline Table get(const K& k);

        int m_stackPos;
        RefCount* m_ref;
        const void* m_table;
        lua_State* m_luaState;
    };

	template<typename K, typename V>
	inline V Table::get(const K& k) {
		if (valid()) {
			pushValue(m_luaState, k);
			lua_gettable(m_luaState, m_stackPos);
		}
		else {
			lua_pushnil(m_luaState);
		}

		V result = readValue<V>(m_luaState, -1);
		lua_pop(m_luaState, 1);
		return result;
	}

	template<typename V>
	inline V Table::get(int k) {
		if (valid()) {
			lua_pushnumber(m_luaState, k);
			lua_gettable(m_luaState, m_stackPos);
		}
		else {
			lua_pushnil(m_luaState);
		}

		V result = readValue<V>(m_luaState, -1);
		lua_pop(m_luaState, 1);
		return result;
	}

	template<typename V>
	inline V Table::get(const char* k) {
		if (valid()) {
			lua_pushstring(m_luaState, k);
			lua_gettable(m_luaState, m_stackPos);
		}
		else {
			lua_pushnil(m_luaState);
		}

		V result = readValue<V>(m_luaState, -1);
		lua_pop(m_luaState, 1);
		return result;
	}

	template<typename K>
	inline Table Table::get(const K& k) {
		if (valid()) {
			pushValue(m_luaState, k);
			lua_gettable(m_luaState, m_stackPos);
		}
		else {
			lua_pushnil(m_luaState);
		}

		return Table(m_luaState, -1);
	}

	template<>
	inline Table Table::get(int k) {
		if (valid()) {
			lua_pushnumber(m_luaState, k);
			lua_gettable(m_luaState, m_stackPos);
		}
		else {
			lua_pushnil(m_luaState);
		}

		return Table(m_luaState, -1);
	}

	template<>
	inline Table Table::get(const char* k) {
		if (valid()) {
			lua_pushstring(m_luaState, k);
			lua_gettable(m_luaState, m_stackPos);
		}
		else {
			lua_pushnil(m_luaState);
		}

		return Table(m_luaState, -1);
	}

    // lua -> cpp
    template<typename T>
    struct ConvertToClass
    {
        inline static T convert(lua_State*L, int idx)
        {
            UserData<T>** ud = static_cast<UserData<T>**>(lua_touserdata(L, idx));
            return *((*ud)->m_obj);
        }
    };

    template<typename T>
    struct ConvertToClass<T&>
    {
        inline static T& convert(lua_State*L, int idx)
        {
            UserData<T>** ud = static_cast<UserData<T>**>(lua_touserdata(L, idx));
            return *((*ud)->m_obj);
        }
    };

    template<typename T>
    struct ConvertToClass<T*>
    {
        inline static T* convert(lua_State*L, int idx)
        {
            UserData<T>** ud = static_cast<UserData<T>**>(lua_touserdata(L, idx));
            return (*ud)->m_obj;
        }
    };

    // cpp -> lua
    template<typename T>
    struct ConvertToLua
    {
        inline static void convert(lua_State* L, T& v)
        {
            UserData<T>** ud = static_cast<UserData<T>**>(lua_newuserdata(L, sizeof(UserData<T>*)));
            *ud = new UserData<T>(new T(v));
            luaL_getmetatable(L, ClassName<T>::name());
            lua_setmetatable(L, -2);
        }
    };

    template<typename T>
    struct ConvertToLua<T&>
    {
        inline static void convert(lua_State* L, T& v)
        {
            UserData<T>** ud = static_cast<UserData<T>**>(lua_newuserdata(L, sizeof(UserData<T>*)));
            *ud = new UserData<T>(&v);
            luaL_getmetatable(L, ClassName<T>::name());
            lua_setmetatable(L, -2);
        }
    };

    template<typename T>
    struct ConvertToLua<T*>
    {
        inline static void convert(lua_State* L, T* v)
        {
            if (v == NULL)
            {
                lua_pushnil(L);
            }
            else
            {
                UserData<T>** ud = static_cast<UserData<T>**>(lua_newuserdata(L, sizeof(UserData<T>*)));
                *ud = new UserData<T>(v, false);
                luaL_getmetatable(L, ClassName<T>::name());
                lua_setmetatable(L, -2);
            }  
        }
    };

	template<typename T>	
	inline vector<T> readVector(lua_State *L, int idx)
	{
		Table t = readValue<Table>(L, idx);
		vector<T> v;
		int nLen = (int)luaL_len(t.m_luaState, t.m_stackPos);
		for (int i = 0; i < nLen; ++i)
		{
			T vv = t.get<T>(i + 1);
			v.push_back(vv);
		}
		return v;
	}

	template<typename K, typename V>
	inline map<K, V> readMap(lua_State *L, int idx)
	{
		lua_pushnil(L);		
		map<K, V> m;
		while (lua_next(L, idx) != 0)
		{
			lua_pushvalue(L, -2);
			K k = readValue<K>(L, -1);
			V v = readValue<V>(L, -2);
			m.insert(make_pair(k, v));
			lua_pop(L, 2);
		}
		return m;
	}

	template<typename T1, typename T2>
	struct is_same_type { operator bool() { return false; } };

	template<typename T>
	struct is_same_type<T,T> { operator bool() { return true; } };

    // lua -> cpp
	template<typename T>    inline T                    readValue(lua_State *L, int idx) {if (!lua_isuserdata(L, idx)) {lua_pushfstring(L, "this arg[%d] is not a userdata!\n", idx); lua_error(L); } return ConvertToClass<T>::convert(L, idx);}
    template<>              inline void                 readValue(lua_State *L, int idx) {}
    template<>              inline bool                 readValue(lua_State *L, int idx) {return lua_toboolean(L, idx) ? true : false;}
    template<>              inline char*                readValue(lua_State *L, int idx) {return (char*)lua_tostring(L, idx);}
    template<>              inline const char*          readValue(lua_State *L, int idx) {return (const char*)lua_tostring(L, idx);}
    template<>              inline char                 readValue(lua_State *L, int idx) {return (char)lua_tonumber(L, idx);}
    template<>              inline unsigned char        readValue(lua_State *L, int idx) {return (unsigned char)lua_tonumber(L, idx);}
    template<>              inline short                readValue(lua_State *L, int idx) {return (short)lua_tonumber(L, idx);}
    template<>              inline unsigned short       readValue(lua_State *L, int idx) {return (unsigned short)lua_tonumber(L, idx);}
    template<>              inline long                 readValue(lua_State *L, int idx) {return (long)lua_tonumber(L, idx);}
    template<>              inline unsigned long        readValue(lua_State *L, int idx) {return (unsigned long)lua_tonumber(L, idx);}
    template<>              inline int                  readValue(lua_State *L, int idx) {return (int)lua_tonumber(L, idx);}
    template<>              inline unsigned int         readValue(lua_State *L, int idx) {return (unsigned int)lua_tonumber(L, idx);}
    template<>              inline long long            readValue(lua_State *L, int idx) {return (long long)lua_tonumber(L, idx);}
    template<>              inline unsigned long long   readValue(lua_State *L, int idx) {return (unsigned long long)lua_tonumber(L, idx);}
    template<>              inline float                readValue(lua_State *L, int idx) {return (float)lua_tonumber(L, idx);}
    template<>              inline double               readValue(lua_State *L, int idx) {return (double)lua_tonumber(L, idx);}
    template<>              inline string               readValue(lua_State *L, int idx) {size_t len; const char* s= (const char*)lua_tolstring(L, idx, &len); return string(s, len);}
    template<>              inline Table                readValue(lua_State *L, int idx) {return Table(L, idx);}

	template<>				inline vector<bool>					readValue(lua_State *L, int idx) { return readVector<bool>(L, idx); }
	template<>				inline vector<char>					readValue(lua_State *L, int idx) { return readVector<char>(L, idx); }
	template<>				inline vector<unsigned char>		readValue(lua_State *L, int idx) { return readVector<unsigned char>(L, idx); }
	template<>				inline vector<short>				readValue(lua_State *L, int idx) { return readVector<short>(L, idx); }
	template<>				inline vector<unsigned short>		readValue(lua_State *L, int idx) { return readVector<unsigned short>(L, idx); }
	template<>				inline vector<int>					readValue(lua_State *L, int idx) { return readVector<int>(L, idx); }
	template<>				inline vector<unsigned int>			readValue(lua_State *L, int idx) { return readVector<unsigned int>(L, idx); }
	template<>				inline vector<long long>			readValue(lua_State *L, int idx) { return readVector<long long>(L, idx); }
	template<>				inline vector<unsigned long long>	readValue(lua_State *L, int idx) { return readVector<unsigned long long>(L, idx); }
	template<>				inline vector<string>				readValue(lua_State *L, int idx) { return readVector<string>(L, idx); }

	template<>				inline map<char, bool>					readValue(lua_State *L, int idx) { return readMap<char, bool>(L, idx); }
	template<>				inline map<char, char>					readValue(lua_State *L, int idx) { return readMap<char, char>(L, idx); }
	template<>				inline map<char, unsigned char>			readValue(lua_State *L, int idx) { return readMap<char, unsigned char>(L, idx); }
	template<>				inline map<char, short>					readValue(lua_State *L, int idx) { return readMap<char, short>(L, idx); }
	template<>				inline map<char, unsigned short>		readValue(lua_State *L, int idx) { return readMap<char, unsigned short>(L, idx); }
	template<>				inline map<char, int>					readValue(lua_State *L, int idx) { return readMap<char, int>(L, idx); }
	template<>				inline map<char, unsigned int>			readValue(lua_State *L, int idx) { return readMap<char, unsigned int>(L, idx); }
	template<>				inline map<char, long long>				readValue(lua_State *L, int idx) { return readMap<char, long long>(L, idx); }
	template<>				inline map<char, unsigned long long>	readValue(lua_State *L, int idx) { return readMap<char, unsigned long long>(L, idx); }
	template<>				inline map<char, string>				readValue(lua_State *L, int idx) { return readMap<char, string>(L, idx); }

	template<>				inline map<unsigned char, bool>					readValue(lua_State *L, int idx) { return readMap<unsigned char, bool>(L, idx); }
	template<>				inline map<unsigned char, char>					readValue(lua_State *L, int idx) { return readMap<unsigned char, char>(L, idx); }
	template<>				inline map<unsigned char, unsigned char>		readValue(lua_State *L, int idx) { return readMap<unsigned char, unsigned char>(L, idx); }
	template<>				inline map<unsigned char, short>				readValue(lua_State *L, int idx) { return readMap<unsigned char, short>(L, idx); }
	template<>				inline map<unsigned char, unsigned short>		readValue(lua_State *L, int idx) { return readMap<unsigned char, unsigned short>(L, idx); }
	template<>				inline map<unsigned char, int>					readValue(lua_State *L, int idx) { return readMap<unsigned char, int>(L, idx); }
	template<>				inline map<unsigned char, unsigned int>			readValue(lua_State *L, int idx) { return readMap<unsigned char, unsigned int>(L, idx); }
	template<>				inline map<unsigned char, long long>			readValue(lua_State *L, int idx) { return readMap<unsigned char, long long>(L, idx); }
	template<>				inline map<unsigned char, unsigned long long>	readValue(lua_State *L, int idx) { return readMap<unsigned char, unsigned long long>(L, idx); }
	template<>				inline map<unsigned char, string>				readValue(lua_State *L, int idx) { return readMap<unsigned char, string>(L, idx); }

	template<>				inline map<short, bool>					readValue(lua_State *L, int idx) { return readMap<short, bool>(L, idx); }
	template<>				inline map<short, char>					readValue(lua_State *L, int idx) { return readMap<short, char>(L, idx); }
	template<>				inline map<short, unsigned char>		readValue(lua_State *L, int idx) { return readMap<short, unsigned char>(L, idx); }
	template<>				inline map<short, short>				readValue(lua_State *L, int idx) { return readMap<short, short>(L, idx); }
	template<>				inline map<short, unsigned short>		readValue(lua_State *L, int idx) { return readMap<short, unsigned short>(L, idx); }
	template<>				inline map<short, int>					readValue(lua_State *L, int idx) { return readMap<short, int>(L, idx); }
	template<>				inline map<short, unsigned int>			readValue(lua_State *L, int idx) { return readMap<short, unsigned int>(L, idx); }
	template<>				inline map<short, long long>			readValue(lua_State *L, int idx) { return readMap<short, long long>(L, idx); }
	template<>				inline map<short, unsigned long long>	readValue(lua_State *L, int idx) { return readMap<short, unsigned long long>(L, idx); }
	template<>				inline map<short, string>				readValue(lua_State *L, int idx) { return readMap<short, string>(L, idx); }

	template<>				inline map<unsigned short, bool>				readValue(lua_State *L, int idx) { return readMap<unsigned short, bool>(L, idx); }
	template<>				inline map<unsigned short, char>				readValue(lua_State *L, int idx) { return readMap<unsigned short, char>(L, idx); }
	template<>				inline map<unsigned short, unsigned char>		readValue(lua_State *L, int idx) { return readMap<unsigned short, unsigned char>(L, idx); }
	template<>				inline map<unsigned short, short>				readValue(lua_State *L, int idx) { return readMap<unsigned short, short>(L, idx); }
	template<>				inline map<unsigned short, unsigned short>		readValue(lua_State *L, int idx) { return readMap<unsigned short, unsigned short>(L, idx); }
	template<>				inline map<unsigned short, int>					readValue(lua_State *L, int idx) { return readMap<unsigned short, int>(L, idx); }
	template<>				inline map<unsigned short, unsigned int>		readValue(lua_State *L, int idx) { return readMap<unsigned short, unsigned int>(L, idx); }
	template<>				inline map<unsigned short, long long>			readValue(lua_State *L, int idx) { return readMap<unsigned short, long long>(L, idx); }
	template<>				inline map<unsigned short, unsigned long long>	readValue(lua_State *L, int idx) { return readMap<unsigned short, unsigned long long>(L, idx); }
	template<>				inline map<unsigned short, string>				readValue(lua_State *L, int idx) { return readMap<unsigned short, string>(L, idx); }

	template<>				inline map<int, bool>				readValue(lua_State *L, int idx) { return readMap<int, bool>(L, idx); }
	template<>				inline map<int, char>				readValue(lua_State *L, int idx) { return readMap<int, char>(L, idx); }
	template<>				inline map<int, unsigned char>		readValue(lua_State *L, int idx) { return readMap<int, unsigned char>(L, idx); }
	template<>				inline map<int, short>				readValue(lua_State *L, int idx) { return readMap<int, short>(L, idx); }
	template<>				inline map<int, unsigned short>		readValue(lua_State *L, int idx) { return readMap<int, unsigned short>(L, idx); }
	template<>				inline map<int, int>				readValue(lua_State *L, int idx) { return readMap<int, int>(L, idx); }
	template<>				inline map<int, unsigned int>		readValue(lua_State *L, int idx) { return readMap<int, unsigned int>(L, idx); }
	template<>				inline map<int, long long>			readValue(lua_State *L, int idx) { return readMap<int, long long>(L, idx); }
	template<>				inline map<int, unsigned long long>	readValue(lua_State *L, int idx) { return readMap<int, unsigned long long>(L, idx); }
	template<>				inline map<int, string>				readValue(lua_State *L, int idx) { return readMap<int, string>(L, idx); }

	template<>				inline map<unsigned int, bool>					readValue(lua_State *L, int idx) { return readMap<unsigned int, bool>(L, idx); }
	template<>				inline map<unsigned int, char>					readValue(lua_State *L, int idx) { return readMap<unsigned int, char>(L, idx); }
	template<>				inline map<unsigned int, unsigned char>			readValue(lua_State *L, int idx) { return readMap<unsigned int, unsigned char>(L, idx); }
	template<>				inline map<unsigned int, short>					readValue(lua_State *L, int idx) { return readMap<unsigned int, short>(L, idx); }
	template<>				inline map<unsigned int, unsigned short>		readValue(lua_State *L, int idx) { return readMap<unsigned int, unsigned short>(L, idx); }
	template<>				inline map<unsigned int, int>					readValue(lua_State *L, int idx) { return readMap<unsigned int, int>(L, idx); }
	template<>				inline map<unsigned int, unsigned int>			readValue(lua_State *L, int idx) { return readMap<unsigned int, unsigned int>(L, idx); }
	template<>				inline map<unsigned int, long long>				readValue(lua_State *L, int idx) { return readMap<unsigned int, long long>(L, idx); }
	template<>				inline map<unsigned int, unsigned long long>	readValue(lua_State *L, int idx) { return readMap<unsigned int, unsigned long long>(L, idx); }
	template<>				inline map<unsigned int, string>				readValue(lua_State *L, int idx) { return readMap<unsigned int, string>(L, idx); }

	template<>				inline map<long long, bool>					readValue(lua_State *L, int idx) { return readMap<long long, bool>(L, idx); }
	template<>				inline map<long long, char>					readValue(lua_State *L, int idx) { return readMap<long long, char>(L, idx); }
	template<>				inline map<long long, unsigned char>		readValue(lua_State *L, int idx) { return readMap<long long, unsigned char>(L, idx); }
	template<>				inline map<long long, short>				readValue(lua_State *L, int idx) { return readMap<long long, short>(L, idx); }
	template<>				inline map<long long, unsigned short>		readValue(lua_State *L, int idx) { return readMap<long long, unsigned short>(L, idx); }
	template<>				inline map<long long, int>					readValue(lua_State *L, int idx) { return readMap<long long, int>(L, idx); }
	template<>				inline map<long long, unsigned int>			readValue(lua_State *L, int idx) { return readMap<long long, unsigned int>(L, idx); }
	template<>				inline map<long long, long long>			readValue(lua_State *L, int idx) { return readMap<long long, long long>(L, idx); }
	template<>				inline map<long long, unsigned long long>	readValue(lua_State *L, int idx) { return readMap<long long, unsigned long long>(L, idx); }
	template<>				inline map<long long, string>				readValue(lua_State *L, int idx) { return readMap<long long, string>(L, idx); }

	template<>				inline map<unsigned long long, bool>				readValue(lua_State *L, int idx) { return readMap<unsigned long long, bool>(L, idx); }
	template<>				inline map<unsigned long long, char>				readValue(lua_State *L, int idx) { return readMap<unsigned long long, char>(L, idx); }
	template<>				inline map<unsigned long long, unsigned char>		readValue(lua_State *L, int idx) { return readMap<unsigned long long, unsigned char>(L, idx); }
	template<>				inline map<unsigned long long, short>				readValue(lua_State *L, int idx) { return readMap<unsigned long long, short>(L, idx); }
	template<>				inline map<unsigned long long, unsigned short>		readValue(lua_State *L, int idx) { return readMap<unsigned long long, unsigned short>(L, idx); }
	template<>				inline map<unsigned long long, int>					readValue(lua_State *L, int idx) { return readMap<unsigned long long, int>(L, idx); }
	template<>				inline map<unsigned long long, unsigned int>		readValue(lua_State *L, int idx) { return readMap<unsigned long long, unsigned int>(L, idx); }
	template<>				inline map<unsigned long long, long long>			readValue(lua_State *L, int idx) { return readMap<unsigned long long, long long>(L, idx); }
	template<>				inline map<unsigned long long, unsigned long long>	readValue(lua_State *L, int idx) { return readMap<unsigned long long, unsigned long long>(L, idx); }
	template<>				inline map<unsigned long long, string>				readValue(lua_State *L, int idx) { return readMap<unsigned long long, string>(L, idx); }

	template<>				inline map<string, bool>				readValue(lua_State *L, int idx) { return readMap<string, bool>(L, idx); }
	template<>				inline map<string, char>				readValue(lua_State *L, int idx) { return readMap<string, char>(L, idx); }
	template<>				inline map<string, unsigned char>		readValue(lua_State *L, int idx) { return readMap<string, unsigned char>(L, idx); }
	template<>				inline map<string, short>				readValue(lua_State *L, int idx) { return readMap<string, short>(L, idx); }
	template<>				inline map<string, unsigned short>		readValue(lua_State *L, int idx) { return readMap<string, unsigned short>(L, idx); }
	template<>				inline map<string, int>					readValue(lua_State *L, int idx) { return readMap<string, int>(L, idx); }
	template<>				inline map<string, unsigned int>		readValue(lua_State *L, int idx) { return readMap<string, unsigned int>(L, idx); }
	template<>				inline map<string, long long>			readValue(lua_State *L, int idx) { return readMap<string, long long>(L, idx); }
	template<>				inline map<string, unsigned long long>	readValue(lua_State *L, int idx) { return readMap<string, unsigned long long>(L, idx); }
	template<>				inline map<string, string>				readValue(lua_State *L, int idx) { return readMap<string, string>(L, idx); }

    template<typename T>    inline T                                readValue(lua_State* L , const char* name)
    {
        lua_getglobal(L, name);
        T v = readValue<T>(L, -1);
        lua_pop(L, 1);
        return v;
    }

	template<typename K, typename T>
	inline void pushMap(lua_State *L, map<K, T> &v)
	{
		Table t(L); 
		for (typename map<K, T>::iterator it = v.begin(); it != v.end(); it++)
		{
			if (ClassName<T>::name() != NULL)
			{
				t.set(it->first, &it->second);
			}
			else
			{
				t.set(it->first, it->second);
			}
		}
		pushValue(L, t);
	}

	template<typename K, typename T>
	inline void pushMap(lua_State *L, map<K, T*> &v)
	{
		Table t(L);
		for (typename map<K, T*>::iterator it = v.begin(); it != v.end(); it++)
		{
			t.set(it->first, it->second);
		}
		pushValue(L, t);
	}

	template<typename T>
	inline void pushVector(lua_State *L, vector<T> &v)
	{ 
		Table t(L); 
		for (size_t i = 0; i < v.size(); i++) 
		{
			if (ClassName<T>::name() != NULL)
			{
				t.set((int)i + 1, &v.at(i));
			}
			else
			{
				t.set((int)i + 1, v.at(i));
			}
		}
		pushValue(L, t); 
	}

	template<typename T>
	inline void pushVector(lua_State *L, vector<T*> &v)
	{
		Table t(L);
		for (size_t i = 0; i < v.size(); i++)
		{
			t.set((int)i + 1, v.at(i));
		}
		pushValue(L, t);
	}

    // cpp -> lua
	template<>              inline void pushValue(lua_State *L, bool v) { lua_pushboolean(L, v); }
	template<>              inline void pushValue(lua_State *L, char v) { lua_pushinteger(L, v); }
	template<>              inline void pushValue(lua_State *L, unsigned char v) { lua_pushinteger(L, v); }
	template<>              inline void pushValue(lua_State *L, short v) { lua_pushinteger(L, v); }
	template<>              inline void pushValue(lua_State *L, unsigned short v) { lua_pushinteger(L, v); }
	template<>              inline void pushValue(lua_State *L, long v) { lua_pushinteger(L, v); }
	template<>              inline void pushValue(lua_State *L, unsigned long v) { lua_pushinteger(L, v); }
	template<>              inline void pushValue(lua_State *L, int v) { lua_pushinteger(L, v); }
	template<>              inline void pushValue(lua_State *L, unsigned int v) { lua_pushinteger(L, v); }
	template<>              inline void pushValue(lua_State *L, long long v) { lua_pushinteger(L, v); }
	template<>              inline void pushValue(lua_State *L, unsigned long long v) { lua_pushinteger(L, v); }
	template<>              inline void pushValue(lua_State *L, float v) { lua_pushnumber(L, v); }
	template<>              inline void pushValue(lua_State *L, double v) { lua_pushnumber(L, v); }
	template<>              inline void pushValue(lua_State *L, char* v) { lua_pushstring(L, v); }
	template<>              inline void pushValue(lua_State *L, const char* v) { lua_pushstring(L, v); }
	template<>              inline void pushValue(lua_State *L, string v) { lua_pushlstring(L, v.c_str(), v.size()); }
	template<>              inline void pushValue(lua_State *L, Table v) { if (v.m_ref) lua_pushvalue(L, v.m_stackPos); else lua_pushnil(L); }
	template<typename T>    inline void pushValue(lua_State *L, T v) { ConvertToLua<T>::convert(L, v); }

	template<typename T>    inline void pushValue(lua_State *L, vector<T> &v) { pushVector(L, v); }
	template<typename T>    inline void pushValue(lua_State *L, vector<T> *v) { pushVector(L, *v); }

	template<typename T>	inline void pushValue(lua_State *L, map<char, T> &v) { pushMap(L, v); }
	template<typename T>	inline void pushValue(lua_State *L, map<char, T> *v) { pushMap(L, *v); }
	template<typename T>	inline void pushValue(lua_State *L, map<unsigned char, T> &v) { pushMap(L, v); }
	template<typename T>	inline void pushValue(lua_State *L, map<unsigned char, T> *v) { pushMap(L, *v); }
	template<typename T>	inline void pushValue(lua_State *L, map<short, T> &v) { pushMap(L, v); }
	template<typename T>	inline void pushValue(lua_State *L, map<short, T> *v) { pushMap(L, *v); }
	template<typename T>	inline void pushValue(lua_State *L, map<unsigned short, T> &v) { pushMap(L, v); }
	template<typename T>	inline void pushValue(lua_State *L, map<unsigned short, T> *v) { pushMap(L, *v); }
	template<typename T>	inline void pushValue(lua_State *L, map<int, T> &v) { pushMap(L, v); }
	template<typename T>	inline void pushValue(lua_State *L, map<int, T> *v) { pushMap(L, *v); }
	template<typename T>	inline void pushValue(lua_State *L, map<unsigned int, T> &v) { pushMap(L, v); }
	template<typename T>	inline void pushValue(lua_State *L, map<unsigned int, T> *v) { pushMap(L, *v); }
	template<typename T>	inline void pushValue(lua_State *L, map<long long, T> &v) { pushMap(L, v); }
	template<typename T>	inline void pushValue(lua_State *L, map<long long, T> *v) { pushMap(L, *v); }
	template<typename T>	inline void pushValue(lua_State *L, map<unsigned long long, T> &v) { pushMap(L, v); }
	template<typename T>	inline void pushValue(lua_State *L, map<unsigned long long, T> *v) { pushMap(L, *v); }
	template<typename T>	inline void pushValue(lua_State *L, map<string, T> &v) { pushMap(L, v); }
	template<typename T>	inline void pushValue(lua_State *L, map<string, T> *v) { pushMap(L, *v); }

    // typename P1, ... , typename P9
    #define _MLUA_TN_PP_LIST_0
    #define _MLUA_TN_PP_LIST_1 _MLUA_TN_PP_LIST_0  typename P1
    #define _MLUA_TN_PP_LIST_2 _MLUA_TN_PP_LIST_1, typename P2
    #define _MLUA_TN_PP_LIST_3 _MLUA_TN_PP_LIST_2, typename P3
    #define _MLUA_TN_PP_LIST_4 _MLUA_TN_PP_LIST_3, typename P4
    #define _MLUA_TN_PP_LIST_5 _MLUA_TN_PP_LIST_4, typename P5
    #define _MLUA_TN_PP_LIST_6 _MLUA_TN_PP_LIST_5, typename P6
    #define _MLUA_TN_PP_LIST_7 _MLUA_TN_PP_LIST_6, typename P7
    #define _MLUA_TN_PP_LIST_8 _MLUA_TN_PP_LIST_7, typename P8
    #define _MLUA_TN_PP_LIST_9 _MLUA_TN_PP_LIST_8, typename P9

    // typename T, typename P1, ... , typename P9
    #define _MLUA_TN_T_PP_LIST_0 typename T  _MLUA_TN_PP_LIST_0
    #define _MLUA_TN_T_PP_LIST_1 typename T, _MLUA_TN_PP_LIST_1
    #define _MLUA_TN_T_PP_LIST_2 typename T, _MLUA_TN_PP_LIST_2
    #define _MLUA_TN_T_PP_LIST_3 typename T, _MLUA_TN_PP_LIST_3
    #define _MLUA_TN_T_PP_LIST_4 typename T, _MLUA_TN_PP_LIST_4
    #define _MLUA_TN_T_PP_LIST_5 typename T, _MLUA_TN_PP_LIST_5
    #define _MLUA_TN_T_PP_LIST_6 typename T, _MLUA_TN_PP_LIST_6
    #define _MLUA_TN_T_PP_LIST_7 typename T, _MLUA_TN_PP_LIST_7
    #define _MLUA_TN_T_PP_LIST_8 typename T, _MLUA_TN_PP_LIST_8
    #define _MLUA_TN_T_PP_LIST_9 typename T, _MLUA_TN_PP_LIST_9

    // typename RL, typename P1,  ... , typename P9
    #define _MLUA_TN_RL_PP_LIST_0 typename RL  _MLUA_TN_PP_LIST_0
    #define _MLUA_TN_RL_PP_LIST_1 typename RL, _MLUA_TN_PP_LIST_1
    #define _MLUA_TN_RL_PP_LIST_2 typename RL, _MLUA_TN_PP_LIST_2
    #define _MLUA_TN_RL_PP_LIST_3 typename RL, _MLUA_TN_PP_LIST_3
    #define _MLUA_TN_RL_PP_LIST_4 typename RL, _MLUA_TN_PP_LIST_4
    #define _MLUA_TN_RL_PP_LIST_5 typename RL, _MLUA_TN_PP_LIST_5
    #define _MLUA_TN_RL_PP_LIST_6 typename RL, _MLUA_TN_PP_LIST_6
    #define _MLUA_TN_RL_PP_LIST_7 typename RL, _MLUA_TN_PP_LIST_7
    #define _MLUA_TN_RL_PP_LIST_8 typename RL, _MLUA_TN_PP_LIST_8
    #define _MLUA_TN_RL_PP_LIST_9 typename RL, _MLUA_TN_PP_LIST_9

	// void, typename P1,  ... , typename P9
	#define _MLUA_TN_V_PP_LIST_0 void  _MLUA_TN_PP_LIST_0
	#define _MLUA_TN_V_PP_LIST_1 void, _MLUA_TN_PP_LIST_1
	#define _MLUA_TN_V_PP_LIST_2 void, _MLUA_TN_PP_LIST_2
	#define _MLUA_TN_V_PP_LIST_3 void, _MLUA_TN_PP_LIST_3
	#define _MLUA_TN_V_PP_LIST_4 void, _MLUA_TN_PP_LIST_4
	#define _MLUA_TN_V_PP_LIST_5 void, _MLUA_TN_PP_LIST_5
	#define _MLUA_TN_V_PP_LIST_6 void, _MLUA_TN_PP_LIST_6
	#define _MLUA_TN_V_PP_LIST_7 void, _MLUA_TN_PP_LIST_7
	#define _MLUA_TN_V_PP_LIST_8 void, _MLUA_TN_PP_LIST_8
	#define _MLUA_TN_V_PP_LIST_9 void, _MLUA_TN_PP_LIST_9

    // P1, ... , P9
    #define _MLUA_PP_LIST_0
    #define _MLUA_PP_LIST_1 _MLUA_PP_LIST_0  P1
    #define _MLUA_PP_LIST_2 _MLUA_PP_LIST_1, P2
    #define _MLUA_PP_LIST_3 _MLUA_PP_LIST_2, P3
    #define _MLUA_PP_LIST_4 _MLUA_PP_LIST_3, P4
    #define _MLUA_PP_LIST_5 _MLUA_PP_LIST_4, P5
    #define _MLUA_PP_LIST_6 _MLUA_PP_LIST_5, P6
    #define _MLUA_PP_LIST_7 _MLUA_PP_LIST_6, P7
    #define _MLUA_PP_LIST_8 _MLUA_PP_LIST_7, P8
    #define _MLUA_PP_LIST_9 _MLUA_PP_LIST_8, P9

    // T, P1, ... , P9
    #define _MLUA_T_PP_LIST_0 T  _MLUA_PP_LIST_0
    #define _MLUA_T_PP_LIST_1 T, _MLUA_PP_LIST_1
    #define _MLUA_T_PP_LIST_2 T, _MLUA_PP_LIST_2
    #define _MLUA_T_PP_LIST_3 T, _MLUA_PP_LIST_3
    #define _MLUA_T_PP_LIST_4 T, _MLUA_PP_LIST_4
    #define _MLUA_T_PP_LIST_5 T, _MLUA_PP_LIST_5
    #define _MLUA_T_PP_LIST_6 T, _MLUA_PP_LIST_6
    #define _MLUA_T_PP_LIST_7 T, _MLUA_PP_LIST_7
    #define _MLUA_T_PP_LIST_8 T, _MLUA_PP_LIST_8
    #define _MLUA_T_PP_LIST_9 T, _MLUA_PP_LIST_9

    // RL, P1, P2, ... , P9
    #define _MLUA_RL_PP_LIST_0 RL  _MLUA_PP_LIST_0
    #define _MLUA_RL_PP_LIST_1 RL, _MLUA_PP_LIST_1
    #define _MLUA_RL_PP_LIST_2 RL, _MLUA_PP_LIST_2
    #define _MLUA_RL_PP_LIST_3 RL, _MLUA_PP_LIST_3
    #define _MLUA_RL_PP_LIST_4 RL, _MLUA_PP_LIST_4
    #define _MLUA_RL_PP_LIST_5 RL, _MLUA_PP_LIST_5
    #define _MLUA_RL_PP_LIST_6 RL, _MLUA_PP_LIST_6
    #define _MLUA_RL_PP_LIST_7 RL, _MLUA_PP_LIST_7
    #define _MLUA_RL_PP_LIST_8 RL, _MLUA_PP_LIST_8
    #define _MLUA_RL_PP_LIST_9 RL, _MLUA_PP_LIST_9

    // void, P1,  ... , P9
    #define _MLUA_V_PP_LIST_0 void  _MLUA_PP_LIST_0
    #define _MLUA_V_PP_LIST_1 void, _MLUA_PP_LIST_1
    #define _MLUA_V_PP_LIST_2 void, _MLUA_PP_LIST_2
    #define _MLUA_V_PP_LIST_3 void, _MLUA_PP_LIST_3
    #define _MLUA_V_PP_LIST_4 void, _MLUA_PP_LIST_4
    #define _MLUA_V_PP_LIST_5 void, _MLUA_PP_LIST_5
    #define _MLUA_V_PP_LIST_6 void, _MLUA_PP_LIST_6
    #define _MLUA_V_PP_LIST_7 void, _MLUA_PP_LIST_7
    #define _MLUA_V_PP_LIST_8 void, _MLUA_PP_LIST_8
    #define _MLUA_V_PP_LIST_9 void, _MLUA_PP_LIST_9

    // read params
    #define _MLUA_READ_LIST_0
    #define _MLUA_READ_LIST_1 _MLUA_READ_LIST_0  readValue<P1 >(L, 1)
    #define _MLUA_READ_LIST_2 _MLUA_READ_LIST_1, readValue<P2 >(L, 2)
    #define _MLUA_READ_LIST_3 _MLUA_READ_LIST_2, readValue<P3 >(L, 3)
    #define _MLUA_READ_LIST_4 _MLUA_READ_LIST_3, readValue<P4 >(L, 4)
    #define _MLUA_READ_LIST_5 _MLUA_READ_LIST_4, readValue<P5 >(L, 5)
    #define _MLUA_READ_LIST_6 _MLUA_READ_LIST_5, readValue<P6 >(L, 6)
    #define _MLUA_READ_LIST_7 _MLUA_READ_LIST_6, readValue<P7 >(L, 7)
    #define _MLUA_READ_LIST_8 _MLUA_READ_LIST_7, readValue<P8 >(L, 8)
    #define _MLUA_READ_LIST_9 _MLUA_READ_LIST_8, readValue<P9 >(L, 9)

    // read params
    #define _MLUA_READ2_LIST_0
    #define _MLUA_READ2_LIST_1 _MLUA_READ2_LIST_0  readValue<P1 >(L, 2)
    #define _MLUA_READ2_LIST_2 _MLUA_READ2_LIST_1, readValue<P2 >(L, 3)
    #define _MLUA_READ2_LIST_3 _MLUA_READ2_LIST_2, readValue<P3 >(L, 4)
    #define _MLUA_READ2_LIST_4 _MLUA_READ2_LIST_3, readValue<P4 >(L, 5)
    #define _MLUA_READ2_LIST_5 _MLUA_READ2_LIST_4, readValue<P5 >(L, 6)
    #define _MLUA_READ2_LIST_6 _MLUA_READ2_LIST_5, readValue<P6 >(L, 7)
    #define _MLUA_READ2_LIST_7 _MLUA_READ2_LIST_6, readValue<P7 >(L, 8)
    #define _MLUA_READ2_LIST_8 _MLUA_READ2_LIST_7, readValue<P8 >(L, 9)
    #define _MLUA_READ2_LIST_9 _MLUA_READ2_LIST_8, readValue<P9 >(L, 10)

    // push params
    #define _MLUA_PUSH_LIST_0
    #define _MLUA_PUSH_LIST_1 _MLUA_PUSH_LIST_0  pushValue(L, p1)
    #define _MLUA_PUSH_LIST_2 _MLUA_PUSH_LIST_1; pushValue(L, p2)
    #define _MLUA_PUSH_LIST_3 _MLUA_PUSH_LIST_2; pushValue(L, p3)
    #define _MLUA_PUSH_LIST_4 _MLUA_PUSH_LIST_3; pushValue(L, p4)
    #define _MLUA_PUSH_LIST_5 _MLUA_PUSH_LIST_4; pushValue(L, p5)
    #define _MLUA_PUSH_LIST_6 _MLUA_PUSH_LIST_5; pushValue(L, p6)
    #define _MLUA_PUSH_LIST_7 _MLUA_PUSH_LIST_6; pushValue(L, p7)
    #define _MLUA_PUSH_LIST_8 _MLUA_PUSH_LIST_7; pushValue(L, p8)
    #define _MLUA_PUSH_LIST_9 _MLUA_PUSH_LIST_8; pushValue(L, p9)

    // class method, has return value
    #define MLUA_MAKE(N)\
    template<typename RL, _MLUA_TN_T_PP_LIST_##N>\
    struct ClassFunc##N : Func\
    {\
        typedef RL (T::* TFUNC)(_MLUA_PP_LIST_##N);\
        TFUNC m_func;\
        const char* m_name;\
        ClassFunc##N(const char* name, TFUNC func): m_func(func), m_name(name) {}\
        ~ClassFunc##N() {}\
        inline virtual int call(lua_State* L)\
        {\
            T* obj = readValue<T* >(L, 1);\
            pushValue(L, (obj->*m_func)(_MLUA_READ2_LIST_##N));\
            return 1;\
        }\
    }
    MLUA_MAKE(0); MLUA_MAKE(1); MLUA_MAKE(2); MLUA_MAKE(3); MLUA_MAKE(4); MLUA_MAKE(5); MLUA_MAKE(6); MLUA_MAKE(7); MLUA_MAKE(8); MLUA_MAKE(9);
    #undef MLUA_MAKE

    // class method no return value
    #define MLUA_MAKE(N)\
    template<_MLUA_TN_T_PP_LIST_##N>\
    struct ClassFunc##N<void, _MLUA_T_PP_LIST_##N>: Func\
    {\
        typedef void (T::* TFUNC)(_MLUA_PP_LIST_##N);\
        TFUNC m_func;\
        const char* m_name;\
        ClassFunc##N(const char* name, TFUNC func): m_func(func), m_name(name) {}\
        ~ClassFunc##N() {}\
        inline virtual int call(lua_State* L)\
        {\
            T* obj = readValue<T* >(L, 1);\
           (obj->*m_func)(_MLUA_READ2_LIST_##N);\
            return 0;\
        }\
    }
    MLUA_MAKE(0); MLUA_MAKE(1); MLUA_MAKE(2); MLUA_MAKE(3); MLUA_MAKE(4); MLUA_MAKE(5); MLUA_MAKE(6); MLUA_MAKE(7); MLUA_MAKE(8); MLUA_MAKE(9);
    #undef MLUA_MAKE

    // global method, has return value
    #define MLUA_MAKE(N)\
    template<_MLUA_TN_RL_PP_LIST_##N>\
    struct GlobalFunc##N : Func\
    {\
        typedef RL (* TFUNC)(_MLUA_PP_LIST_##N);\
        TFUNC m_func;\
        const char* m_name;\
        GlobalFunc##N( const char* name, TFUNC func): m_func(func), m_name(name) {}\
        ~GlobalFunc##N() {}\
        inline virtual int call(lua_State *L)\
        {\
            pushValue(L, (*m_func)(_MLUA_READ_LIST_##N));\
            return 1;\
        }\
    }
    MLUA_MAKE(0); MLUA_MAKE(1); MLUA_MAKE(2); MLUA_MAKE(3); MLUA_MAKE(4); MLUA_MAKE(5); MLUA_MAKE(6); MLUA_MAKE(7); MLUA_MAKE(8); MLUA_MAKE(9);
    #undef MLUA_MAKE

    // global method, no return value
    #define MLUA_MAKE(N)\
    template<_MLUA_TN_PP_LIST_##N>\
    struct GlobalFunc##N<_MLUA_V_PP_LIST_##N> : Func\
    {\
        typedef void (* TFUNC)(_MLUA_PP_LIST_##N);\
        TFUNC m_func;\
        const char* m_name;\
        GlobalFunc##N( const char* name, TFUNC func): m_func(func), m_name(name) {}\
        ~GlobalFunc##N() {}\
        inline virtual int call(lua_State *L)\
        {\
            (*m_func)(_MLUA_READ_LIST_##N);\
            return 0;\
        }\
    }
    MLUA_MAKE(0); MLUA_MAKE(1); MLUA_MAKE(2); MLUA_MAKE(3); MLUA_MAKE(4); MLUA_MAKE(5); MLUA_MAKE(6); MLUA_MAKE(7); MLUA_MAKE(8); MLUA_MAKE(9);
    #undef MLUA_MAKE

    // Lua GC
    template<typename T>
    inline int _gc(lua_State* L)
    {
        UserData<T>** ud = static_cast<UserData<T>**>(luaL_checkudata(L, -1, ClassName<T>::name()));
        delete (*ud);
        return 0;
    }

    // register a class, mlua::regClass<T>(L, name, mlua::ctor<T, P1 ... P9>)
    template<typename T, typename F>
    inline void regClass(MLuaState* ML, const char* name, F fctor)
    {
		lua_State* L = ML->l;

        ClassName<T>::name(name);

        // class ctor
        lua_pushcfunction(L, fctor);
        lua_setglobal(L, name);

        // metatable
        luaL_newmetatable(L, name);

        // metatable.__index = metatable
        lua_pushstring(L, "__index");
        lua_pushvalue(L, -2);
        lua_settable(L, -3);

        // metatable.__newindex = metatable
        lua_pushstring(L, "__newindex");
        lua_pushvalue(L, -2);
        lua_settable(L, -3);

        // metatable.__gc = mlua::gc<T>
        lua_pushstring(L, "__gc");
        lua_pushcfunction(L, &_gc<T>);
        lua_rawset(L, -3);

        lua_pop(L, 1);
    }

	// register a global var
	template<typename T>
	inline void regGlobalVar(MLuaState* ML, const char* name, T v)
	{
        lua_State* L = ML->l;
		pushValue(L, v);
		lua_setglobal(L, name);
	}

    template<typename T>
    inline int _newObj(lua_State* L, T* obj)
    {
        UserData<T>** ud = static_cast<UserData<T>**>(lua_newuserdata(L, sizeof(UserData<T>*)));
        *ud = new UserData<T>(obj);

        // self.metatable = class.metatable
        luaL_getmetatable(L, ClassName<T>::name());
        lua_setmetatable(L, -2);

        return 1;
    }    

    // class ctor method, mlua::ctor<T, P1, P2, ...>(L)
    template<typename T>
    inline int ctor(lua_State* L) {return _newObj(L, new T(_MLUA_READ_LIST_0));}

    template<typename T, typename P1>
    inline int ctor(lua_State* L) {return _newObj(L, new T(_MLUA_READ_LIST_1));}

    template<typename T, typename P1, typename P2>
    inline int ctor(lua_State* L) {return _newObj(L, new T(_MLUA_READ_LIST_2));}

    template<typename T, typename P1, typename P2, typename P3>
    inline int ctor(lua_State* L) {return _newObj(L, new T(_MLUA_READ_LIST_3));}

    template<typename T, typename P1, typename P2, typename P3, typename P4>
    inline int ctor(lua_State* L) {return _newObj(L, new T(_MLUA_READ_LIST_4));}

    template<typename T, typename P1, typename P2, typename P3, typename P4, typename P5>
    inline int ctor(lua_State* L) {return _newObj(L, new T(_MLUA_READ_LIST_5));}

    template<typename T, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
    inline int ctor(lua_State* L) {return _newObj(L, new T(_MLUA_READ_LIST_6));}

    template<typename T, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
    inline int ctor(lua_State* L) {return _newObj(L, new T(_MLUA_READ_LIST_7));}

    template<typename T, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
    inline int ctor(lua_State* L) {return _newObj(L, new T(_MLUA_READ_LIST_8));}

    template<typename T, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9>
    inline int ctor(lua_State* L) {return _newObj(L, new T(_MLUA_READ_LIST_9));}

    inline int _funcCall(lua_State* L)
    {
        Func* func = (Func*)lua_touserdata(L, lua_upvalueindex(1));
        return func->call(L);
    }

    #define _MLUA_REG_METHOD_N(N)\
    {\
        lua_State* L = ML->l;\
        luaL_getmetatable(L, ClassName<T>::name());\
        if(lua_istable(L, -1))\
        {\
            ClassFunc##N<RL, _MLUA_T_PP_LIST_##N>* method = new ClassFunc##N<RL, _MLUA_T_PP_LIST_##N>(name, func);\
            ML->g->push(method);\
            lua_pushstring(L, name);\
            lua_pushlightuserdata(L, method);\
            lua_pushcclosure(L, &_funcCall, 1);\
            lua_rawset(L, -3);\
        }\
        else\
        {\
            MLUA_LOG("please register class %s\n",  ClassName<T>::name());\
        }\
        lua_pop(L, 1);\
    }

    // register class member method, mlua::regMethod<T>(L, name, &T::func)
    template<typename T, typename RL>
    inline void regMethod(MLuaState* ML, const char* name, RL (T::*func)()) _MLUA_REG_METHOD_N(0)
    
    template<typename T, typename RL, typename P1>
    inline void regMethod(MLuaState* ML, const char* name, RL (T::*func)(P1)) _MLUA_REG_METHOD_N(1)
    
    template<typename T, typename RL, typename P1, typename P2>
    inline void regMethod(MLuaState* ML, const char* name, RL (T::*func)(P1, P2)) _MLUA_REG_METHOD_N(2)
    
    template<typename T, typename RL, typename P1, typename P2, typename P3>
    inline void regMethod(MLuaState* ML, const char* name, RL (T::*func)(P1, P2, P3)) _MLUA_REG_METHOD_N(3)
    
    template<typename T, typename RL, typename P1, typename P2, typename P3, typename P4>
    inline void regMethod(MLuaState* ML, const char* name, RL (T::*func)(P1, P2, P3, P4)) _MLUA_REG_METHOD_N(4)
    
    template<typename T, typename RL, typename P1, typename P2, typename P3, typename P4, typename P5>
    inline void regMethod(MLuaState* ML, const char* name, RL (T::*func)(P1, P2, P3, P4, P5)) _MLUA_REG_METHOD_N(5)
    
    template<typename T, typename RL, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
    inline void regMethod(MLuaState* ML, const char* name, RL (T::*func)(P1, P2, P3, P4, P5, P6)) _MLUA_REG_METHOD_N(6)
    
    template<typename T, typename RL, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
    inline void regMethod(MLuaState* ML, const char* name, RL (T::*func)(P1, P2, P3, P4, P5, P6, P7)) _MLUA_REG_METHOD_N(7)
    
    template<typename T, typename RL, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
    inline void regMethod(MLuaState* ML, const char* name, RL (T::*func)(P1, P2, P3, P4, P5, P6, P7, P8)) _MLUA_REG_METHOD_N(8)
    
    template<typename T, typename RL, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9>
    inline void regMethod(MLuaState* ML, const char* name, RL (T::*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9)) _MLUA_REG_METHOD_N(9)

    #define _MLUA_REG_FUNC_N(N)\
    {\
        lua_State* L = ML->l;\
        GlobalFunc##N<_MLUA_RL_PP_LIST_##N>* method = new GlobalFunc##N<_MLUA_RL_PP_LIST_##N>(name, func);\
        lua_pushlightuserdata(L, method);\
        lua_pushcclosure(L, _funcCall, 1);\
        lua_setglobal(L, name);\
        ML->g->push(method);\
    }

    // register global func, mlua::regFunc(L, name, &func)
    template<typename RL>
    inline void regFunc(MLuaState* ML, const char* name, RL (*func)()) _MLUA_REG_FUNC_N(0)
    
    template<typename RL, typename P1>
    inline void regFunc(MLuaState* ML, const char* name, RL (*func)(P1)) _MLUA_REG_FUNC_N(1)
    
    template<typename RL, typename P1, typename P2>
    inline void regFunc(MLuaState* ML, const char* name, RL (*func)(P1, P2)) _MLUA_REG_FUNC_N(2)
    
    template<typename RL, typename P1, typename P2, typename P3>
    inline void regFunc(MLuaState* ML, const char* name, RL (*func)(P1, P2, P3)) _MLUA_REG_FUNC_N(3)
    
    template<typename RL, typename P1, typename P2, typename P3, typename P4>
    inline void regFunc(MLuaState* ML, const char* name, RL (*func)(P1, P2, P3, P4)) _MLUA_REG_FUNC_N(4)
    
    template<typename RL, typename P1, typename P2, typename P3, typename P4, typename P5>
    inline void regFunc(MLuaState* ML, const char* name, RL (*func)(P1, P2, P3, P4, P5)) _MLUA_REG_FUNC_N(5)
    
    template<typename RL, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
    inline void regFunc(MLuaState* ML, const char* name, RL (*func)(P1, P2, P3, P4, P5, P6)) _MLUA_REG_FUNC_N(6)
    
    template<typename RL, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
    inline void regFunc(MLuaState* ML, const char* name, RL (*func)(P1, P2, P3, P4, P5, P6, P7)) _MLUA_REG_FUNC_N(7)
    
    template<typename RL, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
    inline void regFunc(MLuaState* ML, const char* name, RL (*func)(P1, P2, P3, P4, P5, P6, P7, P8)) _MLUA_REG_FUNC_N(8)
    
    template<typename RL, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9>
	inline void regFunc(MLuaState* ML, const char* name, RL(*func)(P1, P2, P3, P4, P5, P6, P7, P8, P9)) _MLUA_REG_FUNC_N(9)

    #define _MLUA_LUA_FUNC_COMM\
    {\
        lua_State* L = ML->l;\
        m_luaState = L;\
        m_has = false;\
        m_ref = 0;\
        if (m_luaState == NULL || func_name == NULL) return false;\
        if (module_name)\
        {\
            lua_getglobal(L, module_name);\
            if (!lua_istable(L, -1))\
            {\
                MLUA_LOG("%s is not a lua module!\n", module_name);\
                return false;\
            }\
            lua_getfield (L, -1, func_name);\
            if (!lua_isfunction(L, -1))\
            {\
                MLUA_LOG("%s is not a lua module function!\n", func_name);\
                return false;\
            }\
        }\
        else\
        {\
            lua_getglobal(L, func_name);\
            if (!lua_isfunction(L, -1))\
            {\
                MLUA_LOG("%s is not a lua global function!\n", func_name);\
                return false;\
            }\
        }\
        m_ref = luaL_ref(L, LUA_REGISTRYINDEX);\
        m_has = true;\
        return true;\
    }\
    ~LuaFunc()\
    {\
        if (m_has) luaL_unref(m_luaState, LUA_REGISTRYINDEX, m_ref);\
        m_luaState = NULL;\
    }\
    int m_ref;\
    bool m_has;\
    lua_State* m_luaState;

	#define _MLUA_LUA_FUNC_EXEC_V(N) {\
		lua_State* L = m_luaState;\
        lua_pushcclosure(L, errorLog, 0);\
        int stackTop = lua_gettop(L);\
        lua_rawgeti(L, LUA_REGISTRYINDEX, m_ref);\
        _MLUA_PUSH_LIST_##N;\
        lua_pcall(L, N, 1, stackTop);\
        lua_settop(L, -3);\
    }

    #define _MLUA_LUA_FUNC_EXEC_R(N) {\
		lua_State* L = m_luaState;\
        lua_pushcclosure(L, errorLog, 0);\
        int stackTop = lua_gettop(L);\
        lua_rawgeti(L, LUA_REGISTRYINDEX, m_ref);\
        _MLUA_PUSH_LIST_##N;\
        lua_pcall(L, N, 1, stackTop);\
        RL result = readValue<RL>(L, -1);\
        lua_settop(L, -3);\
        return result;\
    }

    #define _MLUA_LUA_FUNC_EXEC_T(N) {\
		lua_State* L = m_luaState;\
        lua_pushcclosure(L, errorLog, 0);\
        int stackTop = lua_gettop(L);\
        lua_rawgeti(L, LUA_REGISTRYINDEX, m_ref);\
        _MLUA_PUSH_LIST_##N;\
        lua_pcall(L, N, 1, stackTop);\
        lua_remove(L, -2);\
        return Table(L, -1);\
    }

    // call lua func, has return value, mlua::LuaFunc f(L, "func_name", "module_name"); T t = f(p1, ..., p9);
    template<typename RL>
    struct LuaFunc
    {
        LuaFunc() {init(NULL, NULL, NULL);}

        LuaFunc(MLuaState* ML, const char* func_name, const char* module_name = NULL) {init(ML, func_name, module_name);}

        bool init(MLuaState* ML, const char* func_name, const char* module_name = NULL) _MLUA_LUA_FUNC_COMM

		bool isfunc() {return m_has;}

        RL operator()() _MLUA_LUA_FUNC_EXEC_R(0)

        template<typename P1>
        RL operator()(P1 p1) _MLUA_LUA_FUNC_EXEC_R(1)

        template<typename P1, typename P2>
        RL operator()(P1 p1, P2 p2) _MLUA_LUA_FUNC_EXEC_R(2)

        template<typename P1, typename P2, typename P3>
        RL operator()(P1 p1, P2 p2, P3 p3) _MLUA_LUA_FUNC_EXEC_R(3)

        template<typename P1, typename P2, typename P3, typename P4>
        RL operator()(P1 p1, P2 p2, P3 p3, P4 p4) _MLUA_LUA_FUNC_EXEC_R(4)

        template<typename P1, typename P2, typename P3, typename P4, typename P5>
        RL operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) _MLUA_LUA_FUNC_EXEC_R(5)

        template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
        RL operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) _MLUA_LUA_FUNC_EXEC_R(6)

        template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
        RL operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) _MLUA_LUA_FUNC_EXEC_R(7)

        template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
        RL operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) _MLUA_LUA_FUNC_EXEC_R(8)

        template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9>
        RL operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) _MLUA_LUA_FUNC_EXEC_R(9)
    };

	// call lua func, return value is table, mlua::LuaFunc f(L, "func_name", "module_name"); mlua::Table t = f(p1, ..., p9);
	template<>
	struct LuaFunc<Table>
	{
		LuaFunc() {init(NULL, NULL, NULL);}
        
        LuaFunc(MLuaState* ML, const char* func_name, const char* module_name = NULL) {init(ML, func_name, module_name);}

        bool init(MLuaState* ML, const char* func_name, const char* module_name = NULL) _MLUA_LUA_FUNC_COMM

		bool isfunc() {return m_has;}

		Table operator()() _MLUA_LUA_FUNC_EXEC_T(0)

		template<typename P1>
		Table operator()(P1 p1) _MLUA_LUA_FUNC_EXEC_T(1)

		template<typename P1, typename P2>
		Table operator()(P1 p1, P2 p2) _MLUA_LUA_FUNC_EXEC_T(2)

		template<typename P1, typename P2, typename P3>
		Table operator()(P1 p1, P2 p2, P3 p3) _MLUA_LUA_FUNC_EXEC_T(3)

		template<typename P1, typename P2, typename P3, typename P4>
		Table operator()(P1 p1, P2 p2, P3 p3, P4 p4) _MLUA_LUA_FUNC_EXEC_T(4)

		template<typename P1, typename P2, typename P3, typename P4, typename P5>
		Table operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) _MLUA_LUA_FUNC_EXEC_T(5)

		template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		Table operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) _MLUA_LUA_FUNC_EXEC_T(6)

		template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
		Table operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) _MLUA_LUA_FUNC_EXEC_T(7)

		template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
		Table operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) _MLUA_LUA_FUNC_EXEC_T(8)

		template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9>
		Table operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) _MLUA_LUA_FUNC_EXEC_T(9)
	};

	// call lua func, no return value, mlua::LuaFunc f(L, "func_name", "module_name"); f(p1, ..., p9);
	template<>
	struct LuaFunc<void>
	{
		LuaFunc() {init(NULL, NULL, NULL);}
        
        LuaFunc(MLuaState* ML, const char* func_name, const char* module_name = NULL) {init(ML, func_name, module_name);}

        bool init(MLuaState* ML, const char* func_name, const char* module_name = NULL) _MLUA_LUA_FUNC_COMM

        bool isfunc() {return m_has;}

		void operator()() _MLUA_LUA_FUNC_EXEC_V(0)

		template<typename P1>
		void operator()(P1 p1) _MLUA_LUA_FUNC_EXEC_V(1)

		template<typename P1, typename P2>
		void operator()(P1 p1, P2 p2) _MLUA_LUA_FUNC_EXEC_V(2)

		template<typename P1, typename P2, typename P3>
		void operator()(P1 p1, P2 p2, P3 p3) _MLUA_LUA_FUNC_EXEC_V(3)

		template<typename P1, typename P2, typename P3, typename P4>
		void operator()(P1 p1, P2 p2, P3 p3, P4 p4) _MLUA_LUA_FUNC_EXEC_V(4)

		template<typename P1, typename P2, typename P3, typename P4, typename P5>
		void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) _MLUA_LUA_FUNC_EXEC_V(5)

		template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
		void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) _MLUA_LUA_FUNC_EXEC_V(6)

		template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
		void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) _MLUA_LUA_FUNC_EXEC_V(7)

		template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
		void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) _MLUA_LUA_FUNC_EXEC_V(8)

		template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9>
		void operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) _MLUA_LUA_FUNC_EXEC_V(9)
	};

    inline MLuaState* openLua()
    {
        lua_State *L = luaL_newstate();
        if (L == NULL) NULL;

        MLuaState* ML = new MLuaState();
        ML->g = new Garbage();
        ML->l = L;
        luaL_openlibs(L);
        return ML;
    }

    inline bool doFile(MLuaState* ML, const char *fname)
    {
        lua_State *L = ML->l;
        lua_pushcclosure(L, errorLog, 0);
        int stackTop = lua_gettop(L);

        if(luaL_loadfile(L, fname) == 0)
        {
            if(lua_pcall(L, 0, 0, stackTop))
            {
                lua_pop(L, 1);
            }
        }
        else 
        {
            MLUA_LOG("dofile error: %s\n", lua_tostring(L, -1));
            lua_pop(L, 1);
            false;
        }

        lua_pop(L, 1);
        return true;
    }

    inline bool closeLua(MLuaState* ML)
    {        
        lua_close(ML->l);
        ML->g->release();
        delete ML->g;
        delete ML;
        ML = NULL;
        return true;
    }

} // mlua

#endif // _M_LUA_H_